from .stock_order import StockOrder
from .snapshot import Snapshot
from collections import deque
import heapq
from typing import List
from decimal import Decimal
from typing import Dict

class OrderBook:
    def __init__(self, symbol: str = ""):
        # 类型注解，初始化为空的容器
        self._symbol: str = symbol
        self._buy_orders: Dict[Decimal, deque[StockOrder]] = dict()   # 买单，空字典
        self._sell_orders: Dict[Decimal, deque[StockOrder]] = dict()  # 卖单，空字典

        self._buy_prices: List[Decimal] = []    # 买价堆，空列表
        self._sell_prices: List[Decimal] = []   # 卖价堆，空列表

        self._highest_buy_price: Decimal = Decimal("0")  # 当前最高买价
        self._lowest_sell_price: Decimal = Decimal('10000000')  # 当前最低卖价
        self._total_trade_volume: int = 0  # 总成交量
        self._total_trade_value: Decimal = Decimal("0")  # 总成交额
        self._price: Decimal = Decimal("0")  # 最新价格
        self._volume: int = 0  # 最新成交量

        self._timestamp: int = 0  # 当前时间戳，单位为毫秒

        # 订单 ID 自动递增
        # self.order_id_counter = 0

    def set_symbol(self, symbol: str):
        """
        设置交易品种代码
        """
        self._symbol = symbol

    def get_symbol(self) -> str:
        """
        获取交易品种代码
        """
        return self._symbol
    
    def get_timestamp(self) -> int:
        """
        获取当前时间戳
        """
        return self._timestamp
    
    def set_timestamp(self, timestamp: int):
        """
        设置当前时间戳
        """
        self._timestamp = timestamp
    
    def get_price(self) -> Decimal:
        """
        获取最新价格
        """
        return self._price
    
    def get_buyone_price(self) -> Decimal:
        """
        获取当前买一价
        """
        if not self._buy_prices:
            return Decimal("0")
        return -self._buy_prices[0]
    
    def get_sellone_price(self) -> Decimal:
        """
        获取当前卖一价
        """
        if not self._sell_prices:
            return Decimal("0")
        return self._sell_prices[0]

    def get_volume(self) -> int:
        """
        获取最新成交量
        """
        return self._volume    
    
    def get_total_trade_volume(self) -> int:
        """
        获取总成交量
        """
        return self._total_trade_volume
    
    def get_total_trade_value(self) -> Decimal:
        """
        获取总成交额
        """
        return self._total_trade_value
    
    def get_highest_buy_price(self) -> Decimal:
        """
        获取当前最高买价
        """
        return self._highest_buy_price
    
    def get_lowest_sell_price(self) -> Decimal:
        """
        获取当前最低卖价
        """
        return self._lowest_sell_price
    
    def get_buy_orders(self) -> Dict[Decimal, deque[StockOrder]]:
        """
        获取当前买单簿
        """
        return self._buy_orders
    
    def get_sell_orders(self) -> Dict[Decimal, deque[StockOrder]]:
        """
        获取当前卖单簿
        """
        return self._sell_orders
    
    def get_buy_prices(self) -> List[Decimal]:
        """
        获取当前买价堆
        """
        return self._buy_prices
    
    def get_sell_prices(self) -> List[Decimal]:
        """
        获取当前卖价堆
        """
        return self._sell_prices
    
    def cancel_order(self, order: StockOrder) -> bool:
        """
        取消订单：根据 order_id 查找订单并取消，
        同时从订单簿中移除已取消的订单。
        """
        order_price = order.get_price()
        removed = False

        # 买单处理
        if order.is_buy_order():
            if order_price in self._buy_orders:
                queue = self._buy_orders[order_price]
                for o in list(queue):  # 遍历副本，方便删除
                    if o.get_order_id() == order.get_order_id() and not o.is_filled():
                        o.cancel()
                        queue.remove(o)
                        removed = True
                        break
                # 若该价位队列为空，删除此价位并更新堆
                if not queue:
                    del self._buy_orders[order_price]
                    self._buy_prices = [-p for p in self._buy_orders.keys()]
                    heapq.heapify(self._buy_prices)

        # 卖单处理
        else:
            if order_price in self._sell_orders:
                queue = self._sell_orders[order_price]
                for o in list(queue):
                    if o.get_order_id() == order.get_order_id() and not o.is_filled():
                        o.cancel()
                        queue.remove(o)
                        removed = True
                        break
                # 若该价位队列为空，删除此价位并更新堆
                if not queue:
                    del self._sell_orders[order_price]
                    self._sell_prices = list(self._sell_orders.keys())
                    heapq.heapify(self._sell_prices)

        return removed

    # 添加订单到订单簿，并尝试撮合成交
    def add_order_and_match(self, order:StockOrder) -> List[str]:
        # 验证订单状态
        if(order.get_quantity() <= 0):
            raise ValueError("订单数量必须大于0")
        else:
            order.accept()
        # 设置订单时间戳
        self._timestamp = order.get_create_time()
        return self.match_order(order)

    # 尝试撮合订单
    def match_order(self, order:StockOrder) -> List[str]:
        if order.is_buy_order():
            # 买单：找卖单中价格最便宜的进行成交
            while self._sell_prices and order.is_filled() == False:
                best_price = self._sell_prices[0]  # 卖单最优价格
                if best_price > order.get_price():
                    break  # 买入价比卖出最低价还低，无法成交

                queue = self._sell_orders[best_price]
                while queue and order.get_unfilled_quantity() > 0:
                    # 获取卖单队列中的第一个订单
                    sell_order = queue[0]
                    # 成交量取最小值
                    trade_qty = min(order.get_unfilled_quantity(), sell_order.get_unfilled_quantity())
                    # 更新订单状态
                    order.fill(trade_qty, best_price)
                    sell_order.fill(trade_qty, best_price)
                    # 更新总成交量和总成交额
                    self._total_trade_volume += trade_qty
                    self._total_trade_value += trade_qty * best_price
                    # 更新最高买价和最低卖价
                    self._highest_buy_price = max(self._highest_buy_price, best_price)
                    self._lowest_sell_price = min(self._lowest_sell_price, best_price)
                    # 更新最新价格和成交量
                    self._price = best_price
                    self._volume = trade_qty
                    # 卖单已完全成交
                    if sell_order.is_filled() == True:
                        queue.popleft()  # 卖单已完全成交，移除
                # 卖一价全部被成交
                if not queue:
                    heapq.heappop(self._sell_prices)  # 清空该价位
                    del self._sell_orders[best_price]

            # 剩余未成交部分加入买单簿
            if order.is_filled() == False:
                self.add_to_book(order)

        else:  # 卖单
            while self._buy_prices and order.is_filled() == False:
                best_price = -self._buy_prices[0]  # 买单最优价格（需取反）
                if best_price < order.get_price():
                    break  # 卖出价高于买入最高价，无法成交

                queue = self._buy_orders[best_price]
                while queue and order.is_filled() == False:
                    # 获取买单队列中的第一个订单
                    buy_order = queue[0]
                    trade_qty = min(order.get_unfilled_quantity(), buy_order.get_unfilled_quantity())
                    # 更新订单状态
                    order.fill(trade_qty, best_price)
                    buy_order.fill(trade_qty, best_price)
                    # 更新总成交量和总成交额
                    self._total_trade_volume += trade_qty
                    self._total_trade_value += trade_qty * best_price
                    # 更新最高买价和最低卖价
                    self._highest_buy_price = max(self._highest_buy_price, best_price)
                    self._lowest_sell_price = min(self._lowest_sell_price, best_price)
                    # 更新最新价格和成交量
                    self._price = best_price
                    self._volume = trade_qty
                    # 买单已完全成交
                    if buy_order.is_filled() == True:
                        queue.popleft()  # 买单已完全成交，移除
                # 买一价全部被成交
                if not queue:
                    heapq.heappop(self._buy_prices)  # 清空该价位
                    del self._buy_orders[best_price]

            # 剩余未成交部分加入卖单簿
            if order.is_filled() == False:
                self.add_to_book(order)

    # 添加订单到订单簿（按价格和时间排序）
    def add_to_book(self, order: StockOrder):
        """
        将订单加入订单簿（按价格和时间排序）
        """
        order_price: Decimal = order.get_price()
        if order.is_buy_order():
            if order_price not in self._buy_orders:
                self._buy_orders[order_price] = deque()
                heapq.heappush(self._buy_prices, -order_price)  # 存负值形成最大堆
            self._buy_orders[order_price].append(order)
        else:
            if order_price not in self._sell_orders:
                self._sell_orders[order_price] = deque()
                heapq.heappush(self._sell_prices, order_price)
            self._sell_orders[order_price].append(order)

    def _mid_price(self) -> Decimal:
        if not self._buy_orders or not self._sell_orders:
            return Decimal("0")
        max_buy = max(self._buy_orders.keys())
        min_sell = min(self._sell_orders.keys())
        return (max_buy + min_sell) / Decimal("2")

    # 获取当前竞价价格（集合竞价）
    def get_auction_price(self) -> tuple[Decimal | None, Decimal]:
        return 
        

    # 竞价撮合（集合竞价）
    def auction(self):
        auction_price, max_volume = self.get_auction_price()
        if auction_price is None:
            return

        # 撮合买单（≥竞价价） 和 卖单（≤竞价价）
        buy_prices = [p for p in self._buy_orders if p >= auction_price]
        sell_prices = [p for p in self._sell_orders if p <= auction_price]

        buy_prices.sort(reverse=True)  # 优先高价买
        sell_prices.sort()             # 优先低价卖

        for bp in buy_prices:
            buy_queue = self._buy_orders[bp]
            i = 0
            while i < len(buy_queue):
                buy_order = buy_queue[i]
                if buy_order.is_filled():
                    i += 1
                    continue

                for sp in sell_prices:
                    sell_queue = self._sell_orders[sp]
                    j = 0
                    while j < len(sell_queue) and not buy_order.is_filled():
                        sell_order = sell_queue[j]
                        if sell_order.is_filled():
                            j += 1
                            continue
                        trade_qty = min(buy_order.rest_quantity(), sell_order.rest_quantity())
                        # 更新订单状态
                        buy_order.fill(trade_qty, auction_price)
                        sell_order.fill(trade_qty, auction_price)

                        if sell_order.is_filled():
                            j += 1
                    # 移除已清空的队列
                    self._sell_orders[sp] = deque(
                        order for order in self._sell_orders[sp] if not order.is_filled()
                    )
                i += 1

        # 更新总成交量和总成交额
        self._total_trade_volume += max_volume
        self._total_trade_value += max_volume * auction_price
        # 更新最高买价和最低卖价
        self._highest_buy_price = auction_price
        self._lowest_sell_price = auction_price
        # 更新最新价格和成交量
        self._price = auction_price
        self._volume = max_volume

        

        # 清理空订单簿
        self._buy_orders = {p: q for p, q in self._buy_orders.items() if any(not o.is_filled() for o in q)}
        self._sell_orders = {p: q for p, q in self._sell_orders.items() if any(not o.is_filled() for o in q)}

        # 更新买卖价格堆
        self._buy_prices = [-p for p in self._buy_orders.keys()]
        heapq.heapify(self._buy_prices)
        self._sell_prices = list(self._sell_orders.keys())
        heapq.heapify(self._sell_prices)
        return


    # 打印当前订单簿状态
    def print_order_book(self):
        """
        打印当前挂单簿
        """
        print("=== 卖单簿（价格升序） ===")
        for price in sorted(self._sell_orders, reverse=True):
            qty = sum(order.rest_quantity() for order in self._sell_orders[price])
            print(f"{price}: {qty}")
        print("=== 买单簿（价格降序） ===")
        for price in sorted(self._buy_orders, reverse=True):
            qty = sum(order.rest_quantity() for order in self._buy_orders[price])
            print(f"{price}: {qty}")

    def get_snapshot(self) -> Snapshot:
        """
        获取当前订单簿快照
        """
        snapshot = Snapshot()
        snapshot.set_symbol(self._symbol)
        snapshot.set_price(self._price)
        snapshot.set_volume(self._volume)
        snapshot.set_total_trade_volume(self._total_trade_volume)
        snapshot.set_total_trade_value(self._total_trade_value)
        snapshot.set_highest_price_today(self._highest_buy_price)
        snapshot.set_lowest_price_today(self._lowest_sell_price)
        snapshot.set_timestamp(self._timestamp)

        # 添加10档的价格和对应价格上的总数量 从低到高
        for price in sorted(self._sell_orders.keys(), reverse=False)[:10]:
            volume = sum(order.rest_quantity() for order in self._sell_orders[price])
            snapshot.add_sell_price(price)
            snapshot.add_sell_volume(volume)

        # 不够10档时，补齐
        for _ in range(10 - len(snapshot.get_sell_prices())):
            snapshot.add_sell_price(Decimal("0"))
            snapshot.add_sell_volume(0)
        # 添加10档的价格和对应价格上的总数量 从高到底
        for price in sorted(self._buy_orders.keys(), reverse=True)[:10]:
            volume = sum(order.rest_quantity() for order in self._buy_orders[price])
            snapshot.add_buy_price(price)
            snapshot.add_buy_volume(volume)

        # 不够10档时，补齐
        for _ in range(10 - len(snapshot.get_buy_prices())):
            snapshot.add_buy_price(Decimal("0"))
            snapshot.add_buy_volume(0)

        return snapshot
    
    def clear(self):
        """
        清空订单簿，并重置相关状态
        """
        self._buy_orders.clear()
        self._sell_orders.clear()
        self._buy_prices.clear()
        self._sell_prices.clear()
        
        self._highest_buy_price = Decimal("0")
        self._lowest_sell_price = Decimal('10000000')
        self._total_trade_volume = 0
        self._total_trade_value = Decimal("0")
        self._price = Decimal("0")
        self._volume = 0
        self._timestamp = 0